#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>
#include "Log.hpp"
using namespace ns_log;
/*打印日志并exit程序*/

#define CREATE_SEM (IPC_CREAT | IPC_EXCL | 0666)
#define GET_SEM (IPC_CREAT)
#define P_OP (-1) /*P操作*/
#define V_OP (1)  /*V操作*/
const std::string SEM_PATH = "../tmp";
const int proj_id = 123;
const int default_sem_nums = 1;

enum
{
    FTOK_ERROR = 1,
    SEMGET_ERROR,
    SEMCTL_ERROR
};
/*信号量封装--P-V*/
std::string ToHex(int num)
{
    char buf[64];
    sprintf(buf, "0x%x", num);
    return buf;
}
// 产品
class Semaphore
{
private:
    int _fd;

private:
    void PV(int who,int op)
    {
        struct sembuf sem_buf;
        sem_buf.sem_num = who;
        sem_buf.sem_op = op; // 本质是num + op
        sem_buf.sem_flg = SEM_UNDO;
        int n = semop(_fd, &sem_buf, 1);
        if (n < 0)
        {
            LOG(DEBUG, "op = %d失败\n", op);
            return;
        }
    }

public:
    Semaphore(int fd) : _fd(fd)
    {
    }
    void P(int who)
    {
        PV(who,P_OP);
        LOG(DEBUG, "P操作done\n");
    }
    void V(int who)
    {
        PV(who,V_OP);
        LOG(DEBUG, "V操作done\n");
    }
    int Fd() const
    {
        return _fd;
    }
    /*释放过程交给信号量自身*/
    ~Semaphore()
    {
        if (_fd > 0)
        {
            int n = semctl(_fd, 0, IPC_RMID);
            if (n < 0)
            {
                LOG(ERROR, "semctl的IPC_RMID操作异常!,异常信息:%s\n", strerror(errno));
            }
            LOG(DEBUG, "销毁信号量done\n");
        }
    }
};

// 抽象建造者对象
class Builder
{
public:
    /*定义抽象方法*/
    virtual ~Builder(){}
    virtual void BuildKey() = 0;        // 获取键值
    virtual void SetPerm(int perm) = 0; // 设置权限
    virtual void SetSemNum(int num) = 0;
    virtual void SetVal(const std::vector<int> &init_vals) = 0;
    virtual void Init() = 0; // 初始化信号量
    virtual void Build(int flag) = 0;
};

/*具体建造者*/
class SemaphoreBuilder : public Builder
{
private:
    bool init(int fd, int index, int val)
    {
        union semun
        {
            int val;               /* Value for SETVAL */
            struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
            unsigned short *array; /* Array for GETALL, SETALL */
            struct seminfo *__buf; /* Buffer for IPC_INFO
                                      (Linux-specific) */
        } sem_un;
        sem_un.val = val;
        int ret = semctl(fd, index, SETVAL, sem_un);
        if (ret < 0)
        {
            LOG(ERROR, "semctl的SETVAL操作异常!,异常信息:%s\n", strerror(errno));
            return false;
        }
        return true;
    }

public:
    std::shared_ptr<Semaphore> GetSemaphore()
    {
        return _sem;
    }
    // 构建key
    void BuildKey() override
    {
        LOG(DEBUG, "开始build信号量\n");
        // 1.先ftok得到key
        _key = ftok(SEM_PATH.c_str(), proj_id);
        if (_key == -1)
        {
            LOG(ERROR, "ftok操作异常!,异常信息:%s\n", strerror(errno));
            exit(FTOK_ERROR);
        }
        LOG(INFO, "frok的key为:%s\n", ToHex(_key).c_str());
    }
    // 设置get权限
    void SetPerm(int perm) override
    {
        _perm = perm;
    }
    void SetSemNum(int num) override
    {
        _sem_cnts = num;
    }
    void SetVal(const std::vector<int> &init_vals) override
    {
        _init_vals = init_vals;
    }
    // 构建完sem后做的操作！初始化sem
    void Init() override
    {
        if (_sem_cnts > 0 && _sem_cnts == _init_vals.size())
        {
            // 初始化
            for (int i = 0; i < _sem_cnts; i++)
            {
                if (!init(_sem->Fd(), i, _init_vals[i]))
                {
                    exit(SEMCTL_ERROR);
                }
            }
        }
    }
    // 建造产品
    void Build(int flag) override
    {
        // 设置信号量集总量
        int sem_fd = semget(_key, _sem_cnts, flag);
        if (sem_fd == -1)
        {
            LOG(ERROR, "semget操作异常!,异常信息:%s\n", strerror(errno));
            exit(SEMGET_ERROR);
        }
        _sem = std::make_shared<Semaphore>(sem_fd);
    }
    SemaphoreBuilder()
    {
    }
    ~SemaphoreBuilder()
    {
    }

private:
    std::shared_ptr<Semaphore> _sem;
    key_t _key;
    int _perm;
    int _sem_cnts;
    std::vector<int> _init_vals;
};
/*指挥者*/
class Director
{
public:
    Director()
    {
    }
    ~Director()
    {
    }
    void construct(std::shared_ptr<SemaphoreBuilder> &sem_builder, int flag, int num, const std::vector<int> &vals, int perm)
    {
        sem_builder->BuildKey();     // 创建key
        sem_builder->SetPerm(perm);  // 设置权限
        sem_builder->SetVal(vals);   // 设置信号量值
        sem_builder->SetSemNum(num); // 设置信号量个数
        sem_builder->Build(flag);    // build信号量
        if (flag == CREATE_SEM)
        {
            sem_builder->Init(); // 初始化
        }
    }
};